from django.shortcuts import render, redirect, HttpResponse
from django_redis import get_redis_connection
from django.conf import settings
from web import models
from utils.encrytion.encrypt import uid
from utils.Alipay.alipay import AliPay
import datetime
import json


def index(request):
    """
    首页
    :param request:
    :return:
    """
    return render(request, 'index.html')


def price(request):
    """
    会员制
    :param request:
    :return:
    """
    # 获取价格策略（套餐）
    policy_list = models.PricePolicy.objects.filter(category=2)

    return render(request, 'price.html', {'policy_list': policy_list})


def payment(request, policy_id):
    """
    生成支付页面的订单信息
    :param request:
    :param payment_id:
    :return:
    """
    # 1、接收到购买的相应套餐的对象
    policy_object = models.PricePolicy.objects.filter(id=policy_id, category=2).first()
    if not policy_object:
        return redirect('price')

    # 2、接收到购买的相应套餐的年限（number）
    number = request.GET.get('number', '')
    if not number or not number.isdecimal():
        return redirect('price')
    number = int(number)
    if number < 1:
        return redirect('price')

    # 3、计算出用户输入的数量 * 相应套餐的单价 = 理应支付的原价
    # 注：（还要考虑用户之前购买过的套餐使用情况；若最近购买的套餐期限已到期，则按原价支付；
    #      若最近购买的套餐期限仍未到期，但用户希望升级套餐，则应该是理应支付的原价 - 最近购买的套餐还剩余的金额）
    origin_price = int(number) * policy_object.price

    # 4、判断最近是否购买过套餐，购买的套餐到期与否
    #    注：低级升高级可以补差价实现，但高级降低级只能等高级会员制过期后才可以购买低级会员制度或继续使用个人免费版的权限

    # 设置当前用户的会员制度的所剩金额为 0
    balance_money = 0
    recent_transaction_object = None

    # 如果当前用户所拥有的权限类型为 '收费版'；
    if request.tracer.price_policy.category == 2:
        # 获取最近交易记录、计算此交易记录所对应的会员期限、剩余期限、剩余金额
        recent_transaction_object = models.Transaction.objects.filter(user=request.tracer.user, status=2).order_by(
            '-id').first()
        total_timedelta = recent_transaction_object.end_datetime - recent_transaction_object.start_datetime
        balance_timedelta = recent_transaction_object.end_datetime - datetime.datetime.now()

        if total_timedelta == balance_timedelta:
            balance_money = (recent_transaction_object.price / total_timedelta.days) * (balance_timedelta.days - 1)
        else:
            balance_money = (recent_transaction_object.price / total_timedelta.days) * balance_timedelta.days

    if balance_money >= origin_price:
        return redirect('price')

    context = {'pay_category': policy_object.title,
               'policy_id': policy_object.id,
               'number': number,
               'origin_price': origin_price,
               'balance_money': round(balance_money, 2),
               'total_price': (origin_price - round(balance_money, 2))
               }

    conn = get_redis_connection()
    key = f"payment_{request.tracer.user.mobile_phone}"

    # 将订单信息存到redis中，超时时间设置为30分钟！
    conn.set(key, json.dumps(context), ex=60 * 30)

    context['policy_object'] = policy_object
    context['transaction'] = recent_transaction_object

    return render(request, 'payment.html', context)


def pay(request):
    """
    将交易记录存入数据库，且执行支付
    :param request:
    :return:
    """
    conn = get_redis_connection()
    key = 'payment_{}'.format(request.tracer.user.mobile_phone)
    context_string = conn.get(key)
    if not context_string:
        return redirect('price')
    context = json.loads(context_string.decode('utf-8'))

    # 1. 数据库中生成交易记录（待支付）
    #     等支付成功之后，我们需要把订单的状态更新为已支付、开始&结束时间
    order_id = uid(request.tracer.user.mobile_phone)
    total_price = context['total_price']
    pay_category = context['pay_category']
    models.Transaction.objects.create(
        status=1,
        order=order_id,
        user=request.tracer.user,
        price_policy_id=context['policy_id'],
        count=context['number'],
        price=total_price
    )
    # 生成支付链接

    ali_pay = AliPay(
        appid=settings.ALI_APPID,
        app_notify_url=settings.ALI_NOTIFY_URL,
        return_url=settings.ALI_RETURN_URL,
        app_private_key_path=settings.ALI_PRI_KEY_PATH,
        alipay_public_key_path=settings.ALI_PUB_KEY_PATH
    )
    query_params = ali_pay.direct_pay(
        subject=f"Trace平台支付：{pay_category}",  # 商品简单描述
        out_trade_no=order_id,  # 商户订单号
        total_amount=total_price
    )
    pay_url = "{}?{}".format(settings.ALI_GATEWAY, query_params)
    return redirect(pay_url)


def pay_notify(request):
    """ 支付成功之后触发的URL """
    ali_pay = AliPay(
        appid=settings.ALI_APPID,
        app_notify_url=settings.ALI_NOTIFY_URL,
        return_url=settings.ALI_RETURN_URL,
        app_private_key_path=settings.ALI_PRI_KEY_PATH,
        alipay_public_key_path=settings.ALI_PUB_KEY_PATH
    )

    if request.method == 'GET':
        # 只做跳转，判断是否支付成功了，不做订单的状态更新。
        # 支付吧会讲订单号返回：获取订单ID，然后根据订单ID做状态更新 + 认证。
        # 支付宝公钥对支付给我返回的数据request.GET 进行检查，通过则表示这是支付宝返还的接口。
        params = request.GET.dict()
        sign = params.pop('sign', None)
        status = ali_pay.verify(params, sign)
        if status:
            """
            current_datetime = datetime.datetime.now()
            out_trade_no = params['out_trade_no']
            _object = models.Transaction.objects.filter(order=out_trade_no).first()

            _object.status = 2
            _object.start_datetime = current_datetime
            _object.end_datetime = current_datetime + datetime.timedelta(days=365 * _object.count)
            _object.save()
            """
            return HttpResponse('支付完成')
        return HttpResponse('支付失败')
    else:
        from urllib.parse import parse_qs
        body_str = request.body.decode('utf-8')
        post_data = parse_qs(body_str)
        post_dict = {}
        for k, v in post_data.items():
            post_dict[k] = v[0]

        sign = post_dict.pop('sign', None)
        status = ali_pay.verify(post_dict, sign)
        if status:
            current_datetime = datetime.datetime.now()
            out_trade_no = post_dict['out_trade_no']
            _object = models.Transaction.objects.filter(order=out_trade_no).first()

            _object.status = 2
            _object.start_datetime = current_datetime
            _object.end_datetime = current_datetime + datetime.timedelta(days=365 * _object.count)
            _object.save()
            return HttpResponse('success')

        return HttpResponse('error')
